import sys
import uix
import uiutil
import mathUtil
import blue
import lg
import trinity
import base
import uthread
import util
import os
from math import pi
import uicls
import uiconst
from pychartdir import setLicenseCode, DrawArea
setLicenseCode('DIST-0000-05de-f7ec-ffbeURDT-232Q-M544-C2XM-BD6E-C452')
DRAWLVLREG = 1
DRAWLVLCON = 2
DRAWLVLSOL = 3
DRAWLVLSYS = 4
FLIPMAP = -1
CACHEVERSION = 8

def LtoI(v):
    if (v < 2147483648L):
        return int(v)
    else:
        return ~int((~v & 4294967295L))



class Map2D(uicls.Container):
    __guid__ = 'xtriui.Map2D'
    __nonpersistvars__ = []
    __notifyevents__ = ['OnDestinationSet']

    def init(self):
        sm.RegisterNotify(self)
        self.sr.sizefactor = None
        self.sr.sizefactorsize = None
        self.sr.marks = None
        self.Reset()
        self.overlays = uicls.Container(name='overlays', parent=self, clipChildren=1, pos=(0, 0, 0, 0))
        self.sr.areas = uicls.Container(name='areas', parent=self, clipChildren=1, pos=(0, 0, 0, 0))
        self.hilite = blue.os.LoadObject('res:/UI/Component/circle_thinline.blue')
        self.hilite.state = uix.UI_HIDDEN
        self.hilite.color.SetRGB(1.0, 1.0, 1.0, 0.4)
        self.overlays.children.append(self.hilite)
        self.imhere = uicls.Container(name='imhere', parent=self.overlays, align=uiconst.TOPLEFT, width=16, height=16)
        circle = blue.os.LoadObject('res:/UI/Component/circle_thinline.blue')
        circle.color.SetRGB(1.0, 0.0, 0.0, 1.0)
        self.imhere.children.append(circle)
        self.imhere.state = uix.UI_HIDDEN
        self.destination = uicls.Sprite(blue.os.LoadObject('res:/UI/Component/circle_thinline.blue'))
        self.destination.color.SetRGB(1.0, 1.0, 0.0, 1.0)
        self.destination.state = uix.UI_HIDDEN
        self.overlays.children.append(self.destination)
        self.sprite = uicls.Icon(name='mapsprite', parent=self, align=uiconst.TOALL, state=uiconst.UI_DISABLED, color=(1.0, 1.0, 1.0, 0.0))
        self.sprite.tripass = blue.os.LoadObject('res:/UI/Pass/map.blue')
        self.bgSprite = None
        self.dragging = 0
        self.ditherIn = 1
        self.dragAllowed = 0
        self.dataLayer = None
        self.dataToggle = 0
        self.dataArgs = {}
        self.dataLoaded = None
        self.needsize = None
        self.allowAbstract = 1
        self.fillSize = 0.8
        self.mouseHoverGroups = []
        self.cordsAsPortion = {}



    def SetInfoMode(self):
        self.updatemylocationtimer = None
        uix.FlushList(self.imhere.children[1:])
        for each in self.children:
            if (each.name == 'frame'):
                each.Close()




    def MarkAreas(self, areas = []):
        uthread.pool('Map2D::_MarkAreas', self._MarkAreas, areas)



    def _MarkAreas(self, areas):
        size = (self.absoluteRight - self.absoluteLeft)
        uix.Flush(self.sr.areas)
        for area in areas:
            (id, hint, (absX, absY, absZ,), radius, color,) = area
            maxdist = self.GetMaxDist()
            sizefactor = (((size / 2) / maxdist) * self.fillSize)
            x = ((((FLIPMAP * absX) * sizefactor) / float(size)) + 0.5)
            y = (((absZ * sizefactor) / float(size)) + 0.5)
            rad = ((radius * sizefactor) / float(size))
            mark = uicls.Sprite(blue.os.LoadObject('res:/UI/Shared/Maps/maps_area.blue'))
            mark.width = mark.height = int(((rad * size) * 2))
            mark.left = int((int((x * size)) - (mark.width / 2)))
            mark.top = int(((int((y * size)) - (mark.height / 2)) + 1))
            mark.sr.x = x
            mark.sr.y = y
            mark.sr.rad = rad
            mark.state = uix.UI_DISABLED
            mark.color.SetRGB(1.0, 0.2, 0.2)
            self.sr.areas.children.append(mark)




    def SetMarks(self, marks = []):
        uthread.pool('Map2D::SetMarks', self._SetMarks, marks)



    def _SetMarks(self, marks):
        if not uiutil.IsUnder(self, eve.triapp.uilib.desktop):
            return 
        for i in xrange(0, len(marks), 4):
            id = marks[i]
            hint = marks[(i + 1)]
            uiutil.Update(self, 'Map2D::_SetMarks')
            size = max(1, (self.absoluteRight - self.absoluteLeft))
            (x, y,) = self.GetCordsByKeyAsPortion(id, size)
            if ((x is None) or (y is None)):
                return 
            if (self.sr.marks is None):
                self.sr.marks = uicls.Container(name='marks', parent=self, align=uiconst.TOALL, pos=(0, 0, 0, 0), idx=0, state=uix.UI_DISABLED)
            mark = blue.os.LoadObject('res:/UI/Component/circle_thinline.blue')
            mark.left = (x - (mark.width / 2))
            mark.top = ((y - (mark.height / 2)) + 1)
            self.sr.marks.children.append(mark)
            if hint:
                uicls.Label(text=hint, parent=self.sr.marks, left=(mark.left + mark.width), top=(mark.top + 2), autowidth=False, width=min(128, max(64, ((size - mark.left) - mark.width))), state=uiconst.UI_NORMAL)




    def OnDestinationSet(self, destinationID, *args):
        if ((self is None) or self.destroyed):
            return 
        self.CheckDestination()



    def Reset(self):
        self.portion = 0.75
        self.areas = []
        self.orbs = []
        self.hilite = None
        self.imhere = None
        self.overlays = None
        self.lasthilite = None
        self.pickradius = 6
        self.mapitems = []
        self.outsideitems = []
        self.ids = None
        self.idlevel = None
        self.drawlevel = None
        self.clipped = 0
        self.updatemylocationtimer = None
        self.showingtempangle = None
        self.settings = None



    def _OnClose(self):
        sm.UnregisterNotify(self)
        self.updatemylocationtimer = None
        for each in self.overlays.children:
            if (each.name == 'destinationline'):
                if (hasattr(each, 'renderObject') and (each.renderObject and len(each.renderObject.children))):
                    for _each in each.renderObject.children:
                        _each.object.numPoints = 0
                        del _each.object.vectorCurve.keys[:]
                        each.renderObject.children.remove(_each)

                each.renderObject = None
                each.Close()

        self.OnSelectItem = None
        self.Reset()



    def Draw(self, ids, idlevel, drawlevel, needsize):
        _settings = (ids,
         idlevel,
         drawlevel,
         needsize)
        if (_settings == self.settings):
            return 
        else:
            self.settings = _settings
            usecache = 1
            lg.Info('2Dmaps', 'Drawing map, ids/idlevel/drawlevel:', ids, idlevel, drawlevel)
            if (drawlevel <= idlevel):
                return 
            if ((drawlevel == DRAWLVLSYS) and (len(ids) > 1)):
                ids = ids[:1]
            SIZE = needsize
            _ids = {}
            for id in ids:
                _ids[id] = ''

            ids = _ids.keys()
            endid = ''
            if (len(ids) > 1):
                endid = ('%s_' % ids[-1])
            self.ids = ids
            self.idlevel = idlevel
            self.drawlevel = drawlevel
            self.needsize = needsize
            imageid = ('%s_%s_%s_%s_%s_%s' % (ids[0],
             ('_' * max(0, (len(ids) - 2))),
             endid,
             idlevel,
             drawlevel,
             self.fillSize))
            imageid = imageid.replace('.', '')
            if (self.drawlevel == DRAWLVLSYS):
                imageid += ('_' + str(settings.user.ui.Get('solarsystemmapabstract', 0)))
            lg.Info('2Dmaps', ('MapID is: %s' % imageid))
            for each in self.overlays.children:
                if (each.name == 'destinationline'):
                    each.renderObject = None
                    each.Close()

            self.cordsAsPortion = {}
            cache = self.CheckIfCached(imageid)
            if cache:
                mapitems = self.mapitems = cache['items']
                outsideitems = self.outsideitems = cache['outsideitems']
            else:
                mapitems = self.mapitems = self.GetMapData(ids, idlevel, drawlevel)
            if (drawlevel == 4):
                imagePath = self.DrawSolarsystem(ids, imageid, mapitems, SIZE)
                if self.destroyed:
                    return 
                self.CheckMyLocation()
                return imagePath
            (connections, outsideitems,) = self.GetConnectionData(ids, idlevel, drawlevel)
            self.outsideitems = outsideitems
            minx = 1e+100
            maxx = -1e+100
            minz = 1e+100
            maxz = -1e+100
            for item in mapitems:
                minx = min(minx, item.x)
                maxx = max(maxx, item.x)
                minz = min(minz, item.z)
                maxz = max(maxz, item.z)

            mw = (-minx + maxx)
            mh = (-minz + maxz)
            if not (mw and mh):
                return 
            SIZE = (SIZE * 2)
            drawarea = DrawArea()
            drawarea.setTransparentColor(-1)
            drawarea.setSize(SIZE, SIZE, 4278190080L)
            dotrad = [2,
             3,
             4,
             5,
             6][idlevel]
            sizefactor = (min((SIZE / mw), (SIZE / mh)) * self.portion)
            cords = {}
            for item in mapitems[:]:
                if (item.groupID == const.groupRegion):
                    if (drawlevel != 1):
                        continue
                if (item.groupID == const.groupConstellation):
                    if (drawlevel != 2):
                        continue
                x = int((((item.x * sizefactor) - int((minx * sizefactor))) + ((SIZE - (mw * sizefactor)) / 2)))
                y = int((((item.z * sizefactor) - int((minz * sizefactor))) + ((SIZE - (mh * sizefactor)) / 2)))
                cords[item.itemID] = (x,
                 y,
                 dotrad,
                 1,
                 16777215)

            for item in self.outsideitems:
                x = int((((item.x * sizefactor) - int((minx * sizefactor))) + ((SIZE - (mw * sizefactor)) / 2)))
                y = int((((item.z * sizefactor) - int((minz * sizefactor))) + ((SIZE - (mh * sizefactor)) / 2)))
                cords[item.itemID] = (x,
                 y,
                 dotrad,
                 0,
                 None)

            done = []
            i = 0
            for jumptype in connections:
                for pair in jumptype:
                    (fr, to,) = pair
                    if ((fr, to) in done):
                        continue
                    if ((fr in cords) and (to in cords)):
                        drawarea.line(cords[fr][0], cords[fr][1], cords[to][0], cords[to][1], [43520,
                         255,
                         16711680][i])
                        drawarea.line((cords[fr][0] + 1), cords[fr][1], (cords[to][0] + 1), cords[to][1], [43520,
                         255,
                         16711680][i])
                        drawarea.line(cords[fr][0], (cords[fr][1] + 1), cords[to][0], (cords[to][1] + 1), [43520,
                         255,
                         16711680][i])

                i += 1

            for (x, y, dotrad, cordtype, col,) in cords.itervalues():
                if (cordtype == 0):
                    dotrad = (dotrad / 2)
                drawarea.circle(x, y, dotrad, dotrad, 16777215, 16777215)

            self.areas = [ (cords[id][0],
             cords[id][1],
             cords[id][2],
             id) for id in cords.iterkeys() ]
            self.cordsAsPortion = {}
            for id in cords.iterkeys():
                self.cordsAsPortion[id] = ((cords[id][0] / float(SIZE)), (cords[id][1] / float(SIZE)))

            self.CheckMyLocation()
            self.CheckDestination()
            SIZE = (SIZE / 2)
            self.Cache(drawarea, imageid, mapitems, outsideitems, SIZE)
            path = (u'cache:/Temp/Mapbrowser/%s%s.png' % (imageid, SIZE))
            if self.destroyed:
                return 
            self.PlaceMap((u'cache:/Temp/Mapbrowser/%s%s.png' % (imageid, SIZE)))
            return path



    def CheckDestination(self):
        if ((self is None) or self.destroyed):
            return 
        destination = sm.GetService('starmap').GetDestination()
        if (destination and (self.drawlevel == DRAWLVLSOL)):
            (x, y,) = self.GetCordsByKeyAsPortion(destination)
            if ((x is None) or (y is None)):
                return 
            (self.destination.sr.x, self.destination.sr.y,) = (x, y)
            self.destination.state = uix.UI_DISABLED
            destinationPath = sm.GetService('starmap').GetDestinationPath()
            self.DrawDestinationPath(([eve.session.solarsystemid2] + destinationPath))
            self.RefreshOverlays(1)
        else:
            for each in self.overlays.children:
                if (each.name == 'destinationline'):
                    each.renderObject = None
                    each.Close()




    def DrawDestinationPath(self, ids):
        for each in self.overlays.children:
            if (each.name == 'destinationline'):
                each.renderObject = None
                each.Close()

        lineparent = blue.os.CreateInstance('triui.UIWindow')
        lineparent.align = uix.UI_ALCLIENT
        lineparent.name = 'destinationline'
        lineparent.state = uix.UI_DISABLED
        self.overlays.children.append(lineparent)
        lineparent.z = 1
        lineparent.renderObject = trinity.TriTransform()
        line = blue.os.LoadObject('res:/UI/Component/line.blue')
        line.object.zFunc = trinity.TRICMP_ALWAYS
        line.object.numPoints = len(ids)
        line.object.vectorCurve.extrapolation = trinity.TRIEXT_CONSTANT
        (r, g, b, a,) = (1.0, 1.0, 0.0, 0.75)
        line.object.dstBlend = trinity.TRIBLEND_SRCALPHA
        line.object.dstBlend = trinity.TRIBLEND_INVSRCALPHA
        line.object.colorBegin.SetRGB(r, g, b, a)
        line.object.colorEnd.SetRGB(r, g, b, a)
        del line.object.vectorCurve.keys[:]
        i = 0.0
        for id in ids:
            (x, y,) = self.GetCordsByKeyAsPortion(id, (self.absoluteRight - self.absoluteLeft))
            if (x and y):
                pos = trinity.TriVector((float(x) + 2), (-float(y) - 2), 0.0)
                line.object.vectorCurve.AddKey(i, pos, trinity.TriVector(), trinity.TriVector(), trinity.TRIINT_LINEAR)
                i += 3.0

        if (len(line.object.vectorCurve.keys) > 1):
            line.object.vectorCurve.Sort()
            lineparent.renderObject.children.append(line)



    def GetMapData(self, ids, idlevel, drawlevel):
        mapitems = []
        mapsvc = sm.GetService('map')
        cache = mapsvc.GetMapCache()
        items = cache['items']
        hierarchy = cache['hierarchy']
        if (idlevel == 0):
            for _regionID in hierarchy.iterkeys():
                if (_regionID > const.mapWormholeRegionMin):
                    continue
                mapitems.append(items[_regionID].item)
                for _constellationID in hierarchy[_regionID].iterkeys():
                    if (drawlevel >= 2):
                        mapitems.append(items[_constellationID].item)
                    if (drawlevel == 3):
                        for _solarsystemID in hierarchy[_regionID][_constellationID].iterkeys():
                            mapitems.append(items[_solarsystemID].item)



        elif (idlevel == 1):
            for regionID in ids:
                if (regionID > const.mapWormholeRegionMin):
                    continue
                if (util.IsRegion(regionID) and (regionID in items)):
                    mapitems.append(items[regionID].item)
                    for _constellationID in hierarchy[regionID].iterkeys():
                        if (drawlevel >= 2):
                            mapitems.append(items[_constellationID].item)
                        if (drawlevel == 3):
                            for _solarsystemID in hierarchy[regionID][_constellationID].iterkeys():
                                mapitems.append(items[_solarsystemID].item)



        elif (idlevel == 2):
            for constellationID in ids:
                if (constellationID > const.mapWormholeConstellationMin):
                    continue
                if (util.IsConstellation(constellationID) and (constellationID in items)):
                    mapitems.append(items[constellationID].item)
                    _regionID = mapsvc.GetParentLocationID(constellationID)
                    for _solarsystemID in hierarchy[_regionID][constellationID].iterkeys():
                        mapitems.append(items[_solarsystemID].item)


        elif (idlevel == 3):
            for solarsystemID in ids:
                if util.IsSolarSystem(solarsystemID):
                    mapitems += sm.RemoteSvc('config').GetMapObjects(solarsystemID, 0, 0, 0, 1, 0)

        return mapitems



    def GetConnectionData(self, ids, idlevel, drawlevel):
        inside = []
        outside = []
        conninfo = []
        map = sm.GetService('map')
        for id in ids:
            connections = map.GetItemConnections(int(id), (drawlevel == 1), (drawlevel == 2), (drawlevel == 3), 0, 1)
            conninfo.extend(connections)

        reg = []
        con = []
        sol = []
        outsiders = []
        for connection in conninfo:
            (ctype, fromreg, fromcon, fromsol, stargateID, celestialID, tosol, tocon, toreg,) = connection
            (f, t,) = [(const.locationUniverse, const.locationUniverse),
             (fromreg, toreg),
             (fromcon, tocon),
             (fromsol, tosol),
             (stargateID, celestialID)][drawlevel]
            if ((fromreg != toreg) and ((f, t) not in reg)):
                reg.append((f, t))
                if ((idlevel + 1) > DRAWLVLREG):
                    item = map.GetItem(t)
                    if (item and ((item.itemID not in ((reg + con) + sol)) and (item.groupID == [None,
                     const.groupRegion,
                     const.groupConstellation,
                     const.groupSolarSystem][drawlevel]))):
                        outsiders.append(item)
            elif ((fromcon != tocon) and ((f, t) not in con)):
                con.append((f, t))
                if ((idlevel + 1) > DRAWLVLCON):
                    item = map.GetItem(t)
                    if (item and ((item.itemID not in ((reg + con) + sol)) and (item.groupID == [None,
                     const.groupRegion,
                     const.groupConstellation,
                     const.groupSolarSystem][drawlevel]))):
                        outsiders.append(item)
            else:
                if ((fromsol != tosol) and ((f, t) not in sol)):
                    sol.append((f, t))
                    if ((idlevel + 1) > DRAWLVLSOL):
                        item = map.GetItem(t)
                        if (item and ((item.itemID not in ((reg + con) + sol)) and (item.groupID == [None,
                         const.groupRegion,
                         const.groupConstellation,
                         const.groupSolarSystem][drawlevel]))):
                            outsiders.append(item)

        return ((reg,
          con,
          sol), outsiders)



    def SaveSolarsystemCache(self, cache):
        cache.SaveTo('cache:/Map/solarsystems.blue')



    def GetSolarsystemCache(self):
        if blue.ResFile().Open(u'cache:/Map/solarsystems.blue'):
            cache = eve.rot.GetInstance(u'cache:/Map/solarsystems.blue')
        else:
            cache = blue.os.CreateInstance('triui.UIWindow')
        if (cache.data is None):
            cache.data = {}
        return cache



    def Width(self):
        return (self.absoluteRight - self.absoluteLeft)



    def Height(self):
        return (self.absoluteBottom - self.absoluteTop)



    def MyHierarchy(self):
        return (eve.session.regionid,
         eve.session.constellationid,
         eve.session.solarsystemid2,
         eve.session.stationid)



    def PlaceMap(self, imagepath):
        if ((self is None) or self.destroyed):
            return 
        self.sprite.texture.pixels = imagepath
        self.sprite.Invalidate()
        self.sprite.color.a = 1.0
        if self.ditherIn:
            self.sprite.tripass.textureStage0.minFilter = trinity.TRITEXF_POINT
            self.sprite.tripass.textureStage0.maxMipLevel = 4
            uthread.new(self.ZoomIn, self.sprite.tripass)



    def ZoomIn(self, pass0):
        while pass0.textureStage0.maxMipLevel:
            pass0.textureStage0.maxMipLevel = (pass0.textureStage0.maxMipLevel - 1)
            blue.pyos.synchro.Sleep(100)

        if not self.destroyed:
            self.sprite.tripass.textureStage0.maxMipLevel = 0
            self.sprite.tripass.textureStage0.minFilter = trinity.TRITEXF_LINEAR



    def Cache(self, drawarea, imageid, mapitems, outsideitems, orgsize):
        if not self.destroyed:
            filename = (u'%sTemp/Mapbrowser/%s%s.png' % (blue.os.cachepath,
             imageid,
             orgsize))
            tempFile = blue.os.CreateInstance('blue.ResFile')
            tempFile.Create(filename)
            tempFile.Write(drawarea.outPNG2())
            tempFile.Close()
            cachefile = blue.os.CreateInstance('triui.UIWindow')
            areas = self.areas
            cachefile.data = {'items': mapitems,
             'outsideitems': outsideitems,
             'areas': areas,
             'orbs': self.orbs,
             'sizefactor': self.sr.sizefactor,
             'sizefactorsize': self.sr.sizefactorsize,
             'cordsAsPortion': self.cordsAsPortion}
            cachefile.SaveTo((u'cache:/Temp/Mapbrowser/%s.blue' % imageid))
            blue.pyos.synchro.Yield()



    def CheckCacheAndImage(self, imageid, size):
        image = (u'cache:/Temp/Mapbrowser/%s%s.png' % (imageid, size))
        ospath = (unicode(blue.os.cachepath) + (u'Temp/Mapbrowser/%s%s.png' % (imageid, size)))
        cachefile = self.CheckIfCached(imageid)
        imagepath = None
        if blue.ResFile().Open(image):
            imagepath = image
        return (cachefile, imagepath)



    def CheckIfCached(self, imageid):
        if (settings.public.ui.Get('browsercacheversion', CACHEVERSION) != CACHEVERSION):
            util.DelTree(unicode(os.path.join(blue.os.cachepath, u'Temp/Mapbrowser')))
            settings.public.ui.Set('browsercacheversion', CACHEVERSION)
            return 
        else:
            cache = (u'cache:/Temp/Mapbrowser/%s.blue' % imageid)
            cachefile = None
            if blue.ResFile().Open(cache):
                cachefile = eve.rot.GetInstance(cache).data
            return cachefile



    def CheckMyLocation(self):
        if ((self is None) or self.destroyed):
            return 
        self.updatemylocationtimer = None
        self.imhere.sr.x = self.imhere.sr.y = None
        self.imhere.state = uix.UI_HIDDEN
        self.destination.sr.x = self.destination.sr.y = None
        self.destination.state = uix.UI_HIDDEN
        destination = sm.GetService('starmap').GetDestination()
        if ((self.drawlevel < DRAWLVLSYS) or eve.session.stationid):
            for locationID in self.cordsAsPortion.iterkeys():
                if (locationID in self.MyHierarchy()):
                    (self.imhere.sr.x, self.imhere.sr.y,) = self.cordsAsPortion[locationID]
                    self.imhere.state = uix.UI_DISABLED
                if (destination and (locationID == destination)):
                    (self.destination.sr.x, self.destination.sr.y,) = self.cordsAsPortion[locationID]
                    self.destination.state = uix.UI_DISABLED

        elif (self.ids[0] == eve.session.solarsystemid2):
            self.updatemylocationtimer = base.AutoTimer(100, self.UpdateMyLocation)
            uthread.new(self.UpdateMyLocation)
        self.RefreshOverlays(1)



    def UpdateMyLocation(self):
        if not uiutil.IsUnder(self, eve.triapp.uilib.desktop):
            return 
        bp = sm.GetService('michelle').GetBallpark()
        if ((bp is None) or ((self is None) or self.destroyed)):
            self.updatemylocationtimer = None
            return 
        myball = bp.GetBall(eve.session.shipid)
        if (myball is None):
            self.updatemylocationtimer = None
            return 
        size = max(1, (self.absoluteRight - self.absoluteLeft))
        if (size == 1):
            uiutil.Update(self, 'Map2D::UpdateMyLocation')
            size = max(1, (self.absoluteRight - self.absoluteLeft))
        x = y = None
        if (self.allowAbstract and settings.user.ui.Get('solarsystemmapabstract', 0)):
            if not len(self.orbs):
                return 
            (x, y,) = self.GetAbstractPosition(trinity.TriVector(myball.x, 0.0, myball.z), 1)
        elif ((self.sr.sizefactor is not None) and (self.sr.sizefactorsize is not None)):
            maxdist = self.GetMaxDist()
            sizefactor = (((size / 2) / maxdist) * self.fillSize)
            x = ((((FLIPMAP * myball.x) * sizefactor) / float(size)) + 0.5)
            y = (((myball.z * sizefactor) / float(size)) + 0.5)
        if ((x is not None) and (y is not None)):
            self.imhere.sr.x = x
            self.imhere.sr.y = y
            self.imhere.state = uix.UI_DISABLED
        scene = sm.GetService('sceneManager').GetRegisteredScene('default')
        camera = sm.GetService('sceneManager').GetRegisteredCamera('default')
        rot = camera.rotationAroundParent.GetYawPitchRoll()
        look = camera.rotationOfInterest.GetYawPitchRoll()
        if (len(self.imhere.children) < 2):
            pointer = blue.os.LoadObject('res:/UI/Shared/Maps/fov.blue')
            pointer.children[0].z = sm.GetService('z').GetZ()
            pointer.children[1].z = sm.GetService('z').GetZ()
            self.imhere.children.append(pointer)
        self.imhere.children[1].rotation = ((pi - (rot[0] + look[0])) * (180 / pi))
        actualfov = (camera.fieldOfView * (eve.triapp.uilib.desktop.width / float(eve.triapp.uilib.desktop.height)))
        degfov = ((actualfov * (180 / pi)) - 90.0)
        self.imhere.children[1].children[0].children[0].rotation = (degfov / 2)
        self.imhere.children[1].children[1].children[0].rotation = (-degfov / 2)
        if self.showingtempangle:
            if (len(self.imhere.children) == 2):
                pointer = blue.os.LoadObject('res:/UI/Shared/Maps/fov.blue')
                pointer.children[0].z = sm.GetService('z').GetZ()
                pointer.children[1].z = sm.GetService('z').GetZ()
                self.imhere.children.append(pointer)
                pointer.children[0].children[0].control.model.areas[0].areaMaterials[0].emissive.SetRGB(0.0, 0.3, 0.0)
                pointer.children[1].children[0].control.model.areas[0].areaMaterials[0].emissive.SetRGB(0.0, 0.3, 0.0)
            self.imhere.children[2].state = uix.UI_DISABLED
            self.imhere.children[2].rotation = ((pi - (rot[0] + look[0])) * (180 / pi))
            angle = ((self.showingtempangle * (180 / pi)) - 90.0)
            self.imhere.children[2].children[0].children[0].rotation = (angle / 2)
            self.imhere.children[2].children[1].children[0].rotation = (-angle / 2)
        elif (len(self.imhere.children) == 3):
            self.imhere.children[2].state = uix.UI_HIDDEN
        self.RefreshOverlays()



    def SetTempAngle(self, angle):
        if ((self.imhere is None) or (self.imhere.destroyed or (len(self.imhere.children) <= 1))):
            return 
        self.showingtempangle = angle



    def GetRegionColor(self, regionID):
        color = trinity.TriColor()
        color.SetHSV(((float(regionID) * 21) % 360.0), 0.5, 0.8)
        color.a = 0.75
        return color



    def GetAbstractPosition(self, pos, asPortion = 0, size = None):
        if not len(self.orbs):
            return (None, None)
        else:
            dist = pos.Length()
            maxorb = None
            minorb = (0.0, 0)
            for (orbdist, pixelrad, orbititem, SIZE,) in self.orbs:
                if (orbdist < dist):
                    minorb = (orbdist, pixelrad)
                else:
                    if ((orbdist > dist) and (maxorb is None)):
                        maxorb = (orbdist, pixelrad)

            (mindist, minpixelrad,) = minorb
            distInPixels = minpixelrad
            if maxorb:
                (maxdist, maxpixelrad,) = maxorb
                rnge = (maxdist - mindist)
                pixelrnge = (maxpixelrad - minpixelrad)
                posWithinRange = (dist - mindist)
                distInPixels += (pixelrnge * (posWithinRange / rnge))
            sizefactor = (float(distInPixels) / dist)
            if asPortion:
                size = max(1, (self.absoluteRight - self.absoluteLeft))
                return ((float(size) / (((FLIPMAP * pos.x) * sizefactor) + (SIZE / 2))), (float(size) / ((pos.z * sizefactor) + (SIZE / 2))))
            return ((int(((FLIPMAP * pos.x) * sizefactor)) + (SIZE / 2)), (int((pos.z * sizefactor)) + (SIZE / 2)))



    def GetPick(self):
        areas = []
        size = max(1, (self.absoluteRight - self.absoluteLeft))
        radius = 2
        isAbstract = (self.allowAbstract and (settings.user.ui.Get('solarsystemmapabstract', 0) == 1))
        for locationID in self.cordsAsPortion.iterkeys():
            if (len(self.mouseHoverGroups) and (not isAbstract)):
                locationrec = self.GetItemRecord(locationID)[0]
                if ((not locationrec) or (locationrec.groupID not in self.mouseHoverGroups)):
                    continue
            (x, y,) = self.GetCordsByKeyAsPortion(locationID, size)
            if ((x is None) or (y is None)):
                continue
            if (int(((x - radius) - 3)) <= (eve.triapp.uilib.x - self.absoluteLeft) <= int(((x + radius) + 3)) and int(((y - radius) - 3)) <= (eve.triapp.uilib.y - self.absoluteTop) <= int(((y + radius) + 3))):
                areas.append(locationID)

        return areas



    def GetItemRecord(self, getkey):
        for each in self.mapitems:
            if not hasattr(each, 'itemID'):
                continue
            if (each.itemID == getkey):
                return (each, 1)

        for each in self.outsideitems:
            if not hasattr(each, 'itemID'):
                continue
            if (each.itemID == getkey):
                return (each, 0)

        return (None, None)



    def GetCordsByKeyAsPortion(self, locationID, size = None):
        if (size is None):
            return self.cordsAsPortion.get(locationID, (None, None))
        else:
            (x, y,) = self.cordsAsPortion.get(locationID, (None, None))
            if ((x is not None) and (y is not None)):
                return (int((x * size)), int((y * size)))
            return (None, None)



    def ToggleAbstract(self, setTo):
        uthread.new(self._ToggleAbstract, setTo)



    def _ToggleAbstract(self, setTo):
        settings.user.ui.Set('solarsystemmapabstract', setTo)
        self.settings = None
        self.Draw(self.ids, self.idlevel, self.drawlevel, self.needsize)



    def SetSelected(self, ids):
        if ((self is None) or self.destroyed):
            return 
        for each in self.overlays.children[:]:
            if (each.name == 'selected'):
                each.Close()

        for id in ids:
            (x, y,) = self.GetCordsByKeyAsPortion(id)
            if ((x is not None) and (y is not None)):
                newsel = uicls.Container(align=uiconst.TOPLEFT, width=16, height=16)
                newsel.children.append(blue.os.LoadObject('res:/UI/Component/pointer_down_with_circle.blue'))
                newsel.name = 'selected'
                newsel.children[0].color.SetRGB(1.0, 1.0, 1.0, 0.4)
                newsel.sr.x = x
                newsel.sr.y = y
                newsel.state = uix.UI_DISABLED
                self.overlays.children.append(newsel)

        self.RefreshOverlays(1)



    def _OnResize(self):
        if (self.align == uix.UI_ALTOP):
            self.height = (self.absoluteRight - self.absoluteLeft)
        elif (self.align in (uix.UI_ALLEFT, uix.UI_ALRIGHT)):
            self.width = (self.absoluteBottom - self.absoluteTop)
        try:
            self.RefreshOverlays(1)
        except:
            sys.exc_clear()



    def RefreshOverlays(self, update = 0):
        if not uiutil.IsUnder(self, eve.triapp.uilib.desktop):
            return 
        if ((self is None) or (self.destroyed or (not eve.triapp.uilib))):
            return 
        if update:
            uiutil.Update(self, 'Map2D::RefreshOverlays')
        size = (self.absoluteRight - self.absoluteLeft)
        for each in self.sr.areas.children:
            if ((not hasattr(each, 'sr')) or ((getattr(each.sr, 'x', None) is None) and (getattr(each.sr, 'y', None) is None))):
                continue
            each.width = each.height = int(((each.sr.rad * size) * 2))
            each.left = (int((getattr(each.sr, 'x', 0) * size)) - (each.width / 2))
            each.top = ((int((getattr(each.sr, 'y', 0) * size)) - (each.height / 2)) + 1)

        for each in self.overlays.children:
            if ((not hasattr(each, 'sr')) or ((getattr(each.sr, 'x', None) is None) and (getattr(each.sr, 'y', None) is None))):
                continue
            each.left = (int((getattr(each.sr, 'x', 0) * size)) - (each.width / 2))
            each.top = ((int((getattr(each.sr, 'y', 0) * size)) - (each.height / 2)) + 1)




    def _OnClick(self, *args):
        areas = self.GetPick()
        if areas:
            self.OnSelectItem(self, areas[0])



    def _OnMouseDown(self, *args):
        if self.dragAllowed:
            self.dragging = 1



    def _OnMouseUp(self, *args):
        if self.dragging:
            self.left = max((-self.width + 24), min(((self.parent.absoluteRight - self.parent.absoluteLeft) - 24), self.left))
            self.top = max((-self.height + 24), min(((self.parent.absoluteBottom - self.parent.absoluteTop) - 24), self.top))
            uiutil.SetOrder(self, -1)
        self.dragging = 0



    def SetHint(self, hint):
        self.hilite.state = uix.UI_HIDDEN
        self.sr.hint = hint.replace('[ ', '').replace(' ]', '').strip()
        self.hilite.state = uix.UI_DISABLED



    def _OnMouseMove(self, *args):
        if self.dragging:
            self.left = max((-self.width + 24), min(((self.parent.absoluteRight - self.parent.absoluteLeft) - 24), self.left))
            self.top = max((-self.height + 24), min(((self.parent.absoluteBottom - self.parent.absoluteTop) - 24), self.top))
            return 
        areas = self.GetPick()
        if areas:
            if ((areas[0], len(areas)) == self.lasthilite):
                return 
            self.lasthilite = (areas[0], len(areas))
            (x, y,) = self.GetCordsByKeyAsPortion(areas[0], (self.absoluteRight - self.absoluteLeft))
            if ((x is not None) and (y is not None)):
                self.hilite.left = (x - (self.hilite.width / 2))
                self.hilite.top = ((y - (self.hilite.height / 2)) + 1)
                self.hilite.state = uix.UI_DISABLED
                locStr = ''
                for id in areas:
                    (datarec, datahint,) = self.GetDataArgs(id)
                    (item, insider,) = self.GetItemRecord(id)
                    if item:
                        groupname = cfg.invgroups.Get(item.groupID).name
                        if (item.itemName.lower().find(groupname.lower()) >= 0):
                            groupname = ''
                        locStr += ('%s %s%s<br>' % (item.itemName,
                         groupname,
                         datahint))
                        if not insider:
                            parent = sm.GetService('map').GetItem(item.locationID)
                            locStr = ((mls.UI_SHARED_MAPLINKTO % {'linkto': locStr[:-4],
                             'parent': parent.itemName,
                             'group': cfg.invgroups.Get(parent.groupID).name}) + '<br>')

                if (locStr[-4:] == '<br>'):
                    locStr = locStr[:-4]
                self.SetHint(locStr)
                return 
        self.SetHint('')
        self.hilite.state = uix.UI_HIDDEN
        self.lasthilite = None



    def _OnMouseExit(self, *args):
        self.hilite.state = uix.UI_HIDDEN



    def GetMenu(self):
        m = []
        pick = self.GetPick()
        if (len(pick) == 1):
            (item, insider,) = self.GetItemRecord(pick[0])
            m += sm.GetService('menu').CelestialMenu(pick[0], item)
            m += self.GetDataMenu(pick[0])
        else:
            for itemID in pick:
                (item, insider,) = self.GetItemRecord(itemID)
                if item:
                    submenu = sm.GetService('menu').CelestialMenu(itemID, item)
                    submenu += self.GetDataMenu(itemID)
                    if len(submenu):
                        if (item.groupID == const.groupStation):
                            locationName = uix.EditStationName(item.itemName)
                        else:
                            locationName = item.itemName
                        groupname = cfg.invgroups.Get(item.groupID).name
                        if (locationName.lower().find(groupname.lower()) >= 0):
                            groupname = ''
                        locationName += (' %s' % groupname)
                        m.append((locationName, submenu))

            m.sort()
        if not m:
            m = self.GetParentMenu()
        if (self.drawlevel == DRAWLVLSYS):
            if self.allowAbstract:
                isAbstract = (settings.user.ui.Get('solarsystemmapabstract', 0) == 1)
                m += [None, ([mls.UI_SHARED_MAPSHOWABSTRACT, mls.UI_SHARED_MAPSHOWNONABSTRACT][isAbstract],
                  self.ToggleAbstract,
                  ((not isAbstract)))]
        return m



    def GetParentMenu(self):
        return []



    def GetMaxDist(self):
        maxdist = 0.0
        for item in self.mapitems:
            pos = trinity.TriVector(item.x, 0.0, item.z)
            maxdist = max(maxdist, pos.Length())

        return maxdist



    def DrawSolarsystem(self, ids, imageid, mapitems, SIZE):
        if not len(mapitems):
            return 
        else:
            planets = []
            stargates = []
            asteroidbelts = []
            for item in mapitems:
                if (item.groupID == const.groupPlanet):
                    planets.append(item)
                elif (item.groupID == const.groupStargate):
                    stargates.append(item)
                else:
                    if (item.groupID == const.groupAsteroidBelt):
                        asteroidbelts.append(item)

            drawarea = DrawArea()
            drawarea.setTransparentColor(-1)
            drawarea.setSize(SIZE, SIZE, 4278190080L)
            cords = {}
            sunID = None
            maxdist = 0.0
            for item in mapitems:
                pos = trinity.TriVector(item.x, 0.0, item.z)
                maxdist = max(maxdist, pos.Length())
                if (item.groupID == const.groupSun):
                    sunID = item.itemID
                    radius = 3
                    drawarea.circle((SIZE / 2), (SIZE / 2), radius, radius, 10066329, 10066329)

            sizefactor = (((SIZE / 2) / maxdist) * self.fillSize)
            self.sr.sizefactor = sizefactor
            self.sr.sizefactorsize = SIZE
            if (self.allowAbstract and settings.user.ui.Get('solarsystemmapabstract', 0)):
                _planets = []
                for planet in planets:
                    pos = trinity.TriVector(planet.x, planet.y, planet.z)
                    dist = pos.Length()
                    _planets.append([dist, planet])

                _planets = uiutil.SortListOfTuples(_planets)
                planet = _planets
            i = 1
            for item in planets:
                pos = trinity.TriVector(item.x, 0.0, item.z)
                dist = pos.Length()
                if (self.allowAbstract and settings.user.ui.Get('solarsystemmapabstract', 0)):
                    planetscale = ((i * (maxdist / len(planets))) / dist)
                    pos.Scale(planetscale)
                x = (((FLIPMAP * pos.x) * sizefactor) + (SIZE / 2))
                y = ((pos.z * sizefactor) + (SIZE / 2))
                radius = 1
                cords[item.itemID] = (x,
                 y,
                 radius)
                drawarea.circle(x, y, radius, radius, 16777215, LtoI(4278190080L))
                self.AddChilds(x, y, radius, item.itemID, SIZE, drawarea, cords, item)
                i += 1

            self.orbs = []
            for orbit in planets:
                if (orbit.itemID in cords):
                    (x, y, radius,) = cords[orbit.itemID]
                    center = (SIZE / 2)
                    frompos = trinity.TriVector(float(center), 0.0, float(center))
                    topos = trinity.TriVector(float(x), 0.0, float(y))
                    diff = (topos - frompos)
                    rad = int(diff.Length())
                    drawarea.circle(center, center, rad, rad, self.GetColorByGroupID(const.groupPlanet), LtoI(4278190080L))
                    orbpos = trinity.TriVector(orbit.x, 0.0, orbit.z)
                    orbdist = orbpos.Length()
                    self.orbs.append([orbdist, (orbdist,
                      rad,
                      orbit,
                      SIZE)])

            self.orbs = uiutil.SortListOfTuples(self.orbs)
            for item in stargates:
                if (self.allowAbstract and settings.user.ui.Get('solarsystemmapabstract', 0)):
                    if not len(self.orbs):
                        return 
                    (x, y,) = self.GetAbstractPosition(trinity.TriVector(item.x, 0.0, item.z))
                else:
                    x = (((FLIPMAP * self.sr.sizefactor) * item.x) + (self.sr.sizefactorsize / 2))
                    y = ((self.sr.sizefactor * item.z) + (self.sr.sizefactorsize / 2))
                x += 6
                radius = 1
                drawarea.circle(x, y, radius, radius, 0, self.GetColorByGroupID(const.groupStargate))
                cords[item.itemID] = (x,
                 y,
                 radius)

            self.areas = [ (cords[id][0],
             cords[id][1],
             cords[id][2],
             id) for id in cords.iterkeys() ]
            self.cordsAsPortion = {}
            for id in cords.iterkeys():
                self.cordsAsPortion[id] = ((cords[id][0] / float(SIZE)), (cords[id][1] / float(SIZE)))

            self.Cache(drawarea, imageid, mapitems, [], SIZE)
            path = (u'cache:/Temp/Mapbrowser/%s%s.png' % (imageid, SIZE))
            if self.destroyed:
                return 
            self.PlaceMap(path)
            self.PlaceBackground(u'res:/UI/Texture/map_ssunderlay.dds')
            return path



    def AddChilds(self, parentX, parentY, parentRad, parentID, SIZE, draw, cords, parent, _x = None, _y = None):
        parentpos = trinity.TriVector(parent.x, parent.y, parent.z)
        sorted = []
        allchilds = self.GetChilds(parentID, [], 0)
        for child in allchilds:
            childpos = trinity.TriVector(child.x, child.y, child.z)
            diff = (childpos - parentpos)
            dist = diff.Length()
            sorted.append((dist, child))

        sorted = uiutil.SortListOfTuples(sorted)
        if (self.allowAbstract and settings.user.ui.Get('solarsystemmapabstract', 0)):
            done = []
            i = 1
            xi = 0
            for child in sorted:
                if (child.itemID in done):
                    continue
                radius = 1
                step = (max(12, (radius * 4)) - 2)
                y = (_y or ((parentY + parentRad) + (i * step)))
                x = (_x or (parentX + xi))
                if ((y + step) > SIZE):
                    i = 0
                    xi += step
                done.append(child.itemID)
                fill = self.GetColorByGroupID(child.groupID)
                draw.circle(x, y, radius, radius, fill, fill)
                cords[child.itemID] = (x,
                 y,
                 radius)
                i += 1

        else:
            for child in sorted:
                radius = 1
                pos = trinity.TriVector(child.x, 0.0, child.z)
                pos = (pos + ((pos - parentpos) * max(1.0, (4096 / SIZE))))
                x = (((FLIPMAP * pos.x) * self.sr.sizefactor) + (SIZE / 2))
                y = ((pos.z * self.sr.sizefactor) + (SIZE / 2))
                fill = self.GetColorByGroupID(child.groupID)
                draw.circle(x, y, radius, radius, fill, fill)
                cords[child.itemID] = (x,
                 y,
                 radius)




    def GetChilds(self, parentID, childs, i):
        i += 1
        if ((i == 20) or (len(childs) > 1000)):
            return childs
        else:
            _childs = [ child for child in self.mapitems if (child.orbitID == parentID) ]
            if len(_childs):
                childs += _childs
                for granchild in _childs:
                    childs = self.GetChilds(granchild.itemID, childs, i)

            return childs



    def GetColorByGroupID(self, groupID):
        col = {const.groupAsteroidBelt: 255,
         const.groupPlanet: 8947848,
         const.groupStargate: 34816,
         const.groupStation: 16724787}.get(groupID, 10066329)
        return col



    def GetDataArgs(self, locationID):
        if (locationID in self.dataArgs):
            return self.dataArgs[locationID]
        else:
            return (None, '')



    def GetDataMenu(self, locationID):
        (datarec, datahint,) = self.GetDataArgs(locationID)
        if not datarec:
            return []
        else:
            locationrec = self.GetItemRecord(locationID)[0]
            if not locationrec:
                return []
            return self.GetDataMenuExt(self, locationrec, datarec)



    def GetDataMenuExt(self, *args):
        return []



    def Fade(self, what, f, t):
        (start, ndt,) = (blue.os.GetTime(), 0.0)
        while (ndt != 1.0):
            ndt = min((blue.os.TimeDiffInMs(start) / 1000.0), 1.0)
            what.color.a = mathUtil.Lerp(f, t, ndt)
            blue.pyos.synchro.Yield()




    def PlaceBackground(self, imagepath):
        if ((self is None) or self.destroyed):
            return 
        if (self.bgSprite is None):
            self.bgSprite = uicls.Sprite(name='bgSprite', parent=self, align=uiconst.TOALL, state=uiconst.UI_DISABLED, color=(1.0, 1.0, 1.0, 1.0))
            self.bgSprite.tripass = blue.os.LoadObject('res:/UI/Pass/linear.blue')
        self.bgSprite.texture.pixels = imagepath
        self.bgSprite.Invalidate()



    def OnSelectItem(self, _self, arg, *args):
        return 




